// John Lake
// CSCE 441

#include <stdio.h>
#include <list>
#include "./ActiveEdgeTable.h"
#include <gl/glut.h>
#include <gl/gl.h>	//
#include <cmath>	// ?


/******************************************************************
	Notes:
	Image size is 400 by 400 by default.  You may adjust this if
		you want to.
	You can assume the window will NOT be resized.
	Call clearFramebuffer to clear the entire framebuffer.
	Call setFramebuffer to set a pixel.  This should be the only
		routine you use to set the color (other than clearing the
		entire framebuffer).  drawit() will cause the current
		framebuffer to be displayed.
	As is, your scan conversion should probably be called from
		within the display function.  There is a very short sample
		of code there now.
	You may add code to any of the subroutines here,  You probably
		want to leave the drawit, clearFramebuffer, and
		setFramebuffer commands alone, though.
  *****************************************************************/

#define ImageW 800
#define ImageH 800

float framebuffer[ImageH][ImageW][3];

std::list<Polygon*> polyList;	// keep track of (original) polygons drawn in window
std::list<Polygon*> clipList;	// keep track of polygons after clipping
Polygon* inProgress;			// keep track of the polygon currently being drawn
Point p1, p2;					// points used in the implementation
Color next_color;				// used to change the color of the next polygon;
								//    changed on right click (after draw())
bool drawing_rectangle;



// simple function to change the color for the next polygon
void colorUpdate()
{
	double r1, r2;
	r1 = rand();
	r2 = rand();
	printf("new color: %f, %f\n", r1, r2);
	if(r1 > r2)
		next_color.r = r2/r1;	// number between 0 and 1
	else
		next_color.r = r1/r2;	// number between 0 and 1

	r1 = rand();
	r2 = rand();
	if(r1 > r2)
		next_color.g = r2/r1;	// number between 0 and 1
	else
		next_color.g = r1/r2;	// number between 0 and 1

	r1 = rand();
	r2 = rand();
	if(r1 > r2)
		next_color.b = r2/r1;	// number between 0 and 1
	else
		next_color.b = r1/r2;	// number between 0 and 1
}



// Draws the scene
void drawit(void)
{
   glDrawPixels(ImageW,ImageH,GL_RGB,GL_FLOAT,framebuffer);
   glFlush();
}

// Clears framebuffer to black
void clearFramebuffer()
{
	int i,j;

	for(i=0;i<ImageH;i++) {
		for (j=0;j<ImageW;j++) {
			framebuffer[i][j][0] = 0.0;	// R
			framebuffer[i][j][1] = 0.0;	// G
			framebuffer[i][j][2] = 0.0;	// B
		}
	}
}

// Sets pixel x,y to the color RGB
// I've made a small change to this function to make the pixels match
// those returned by the glutMouseFunc exactly - Scott Schaefer 
void setFramebuffer(int x, int y, float R, float G, float B)
{
	// changes the origin from the lower-left corner to the upper-left corner
	y = ImageH - 1 - y;
	if (R<=1.0)
		if (R>=0.0)
			framebuffer[y][x][0]=R;
		else
			framebuffer[y][x][0]=0.0;
	else
		framebuffer[y][x][0]=1.0;
	if (G<=1.0)
		if (G>=0.0)
			framebuffer[y][x][1]=G;
		else
			framebuffer[y][x][1]=0.0;
	else
		framebuffer[y][x][1]=1.0;
	if (B<=1.0)
		if (B>=0.0)
			framebuffer[y][x][2]=B;
		else
			framebuffer[y][x][2]=0.0;
	else
		framebuffer[y][x][2]=1.0;
}


// perhaps problem with random lines is here, in the redrawing?  sounds promising
void display(void)
{
//	clearFramebuffer();	//maybe here
/*
	std::list<Polygon*>::iterator polyListIter;
	int i = 1;	// for the printf (for error checking)
	for(polyListIter = polyList.begin(); 
			polyListIter != polyList.end();
			polyListIter++)
	{	// draw each polygon in the list
		printf("Drawing %d\n", i);
		(*polyListIter)->drawPolygon();	// calls setFramebuffer()
		printf("%d Drawn\n", i);
		i++;
	}
*/
	/*	// print the framebuffer (for error checking)
	for(int i=0;i<ImageH;i++) {
		for (int j=0;j<ImageW;j++) {
			printf("%d", (framebuffer[i][j][0] + framebuffer[i][j][1] + framebuffer[i][j][2]) == 0);
		}
		printf("\n");
	}
	*/


	drawit();
	printf("drawit() called\n");


	//The next two lines of code are for demonstration only.
	//They show how to draw a line from (0,0) to (100,100)
/*
	int i;
	for(i=0;i<=100;i++) setFramebuffer(i,i,1.0,1.0,1.0);
*/
}


// forsee a potential problem getting the old polygons to show up when left clicking;
//    may be better to draw outside of display (i.e. put this in right click
//    and the other code in left click... I like it!  but that's 
void clipDisplay(void)
{	// not needed if other thing works
	drawit();
	printf("drawit() called\n");
}



void mouseDraw(int button, int state, int x, int y)
{
	Point temp;	// probable E better way to do this
	temp.x = x;
	temp.y = y;
	printf("temp:\t%d,%d\n",temp.x,temp.y);

	if(state == GLUT_UP)	// catching the end of a down-press => ignore
		return;

	if(button == GLUT_LEFT_BUTTON)
	{
		if(inProgress == NULL)
		{
			printf("Starting new polgon\n");

			// start polygon
			inProgress = new Polygon(ImageW, ImageH, next_color);

			// store this as starter point
			p1.x = x;
			p1.y = y;

			// store this as the previous point (= starter point)
			p2.x = x;
			p2.y = y;
		}
		else
		{
			Edge* tempEdge = new Edge(p2,temp);
			inProgress->addEdge(tempEdge);
			p2 = temp;
		}
	}
	else if(button == GLUT_RIGHT_BUTTON)
	{
		// add two edges: previous point to here and here to starter point
		Edge* tempEdge1 = new Edge(p2,temp);
		Edge* tempEdge2 = new Edge(temp,p1);

		inProgress->addEdge(tempEdge1);	// edge from previous to this point
		inProgress->addEdge(tempEdge2);	// edge from this point to the starting point

		// put inProgress in the list of polygons
		polyList.push_back(inProgress);
		inProgress->drawPolygon();

		// trigger redrawing
		glutPostRedisplay();

		// clean up
		inProgress = NULL;
		
		// update next_color
		colorUpdate();
	}
	else
	{
		// something wrong?
		printf("\nCap'n!\tWas neither left nor right button!\n\n");
	}

}



// the new function to be called after 
void mouseClip(int button, int state, int x, int y)
{
	printf("Clipping not yet implemented\n");
	clearFramebuffer();

	if(state == GLUT_DOWN)
	{
		p1.x = x; 
		p1.y = y;
		drawing_rectangle = true;


		// draw the old polygons
		std::list<Polygon*>::iterator polyListIter;
		int i = 1;	// for the printf (for error checking)
		for(polyListIter = polyList.begin(); 
				polyListIter != polyList.end();
				polyListIter++)
		{	// draw each polygon in the list
			printf("Drawing %d\n", i);
			(*polyListIter)->drawPolygon();	// calls setFramebuffer()
			printf("%d Drawn\n", i);
			i++;
		}
		drawit();

	}

	if(state == GLUT_UP)
	{
		drawing_rectangle = false;

		// deal with memory leak inside clipList

		// clip
		// Sutherland-Hodgman()
		//    if have time, do the other one
		std::list<Polygon*>::iterator polyListIter;
		int i = 1;	// for the printf (for error checking)
		for(polyListIter = polyList.begin(); 
				polyListIter != polyList.end();
				polyListIter++)
		{	// draw each polygon in the list
			printf("Clipping %d\n", i);
			//clips the polygon and puts the result in the other list
			clipList.push_back((*polyListIter)->clipPolygon((*polyListIter),p1,p2));	
			printf("%d Clipped\n", i);
			i++;
		}


		// draw the clipped polygons
//		clearFramebuffer();	//maybe here
		std::list<Polygon*>::iterator clipListIter;		// don't really need a second one
		i = 1;	// for the printf (for error checking)
		for(clipListIter = clipList.begin(); clipListIter != clipList.end(); clipListIter++)
		{	// draw each polygon in the list
			printf("Drawing clipped %d\n", i);
			(*clipListIter)->drawPolygon();	// calls setFramebuffer()
			printf("%d (clipped) Drawn\n", i);
			i++;
		}

		glutPostRedisplay();

		for(clipListIter = clipList.begin(); clipListIter != clipList.end(); 1)		
			clipListIter = clipList.erase(clipListIter);
	}
}

void mouseClip_Rect(int x, int y)
{
	if((x != p1.x) || (y != p2.y))	// if it's not the same point
		clearFramebuffer();
	// draw the old polygons
	std::list<Polygon*>::iterator polyListIter;
	int i = 1;	// for the printf (for error checking)
	for(polyListIter = polyList.begin(); 
			polyListIter != polyList.end();
			polyListIter++)
	{	// draw each polygon in the list
		printf("Drawing %d\n", i);
		(*polyListIter)->drawPolygon();	// calls setFramebuffer()
		printf("%d Drawn\n", i);
		i++;
	}

	// draw the clipping box
	p2.x = x;
	p2.y = y;
	glBegin ( GL_QUADS );
		glVertex2f ( p1.x, p1.y );
		glVertex2f ( p1.x, p2.y );
		glVertex2f ( p2.x, p2.y );
		glVertex2f ( p2.x, p1.y );
	glEnd ( );
	glFlush();

	glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y)
{
	switch(key) {
	case 'c':
		// enter clipping mode

			//must now pull from the other list of polygons	
		glutInitDisplayMode (GLUT_SINGLE | GLUT_RGBA);	// changed to GLUT_RGBA to allow blending for clipping rectangle
		glEnable (GL_BLEND);
		glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glColor4f(1, 1, 1, 0.1);				// use a white rectangle

//		glutDisplayFunc(display);
		glutMouseFunc( mouseClip );
		glutMotionFunc( mouseClip_Rect );
//		glutKeyboardFunc( keyboard );
//		glutMainLoop();
		break;
		
	default:
		break;
	}

}

void init(void)
{
	gluOrtho2D ( 0, ImageW - 1, ImageH - 1, 0 );
	clearFramebuffer();
}

int main(int argc, char** argv)
{
	inProgress = NULL;
	next_color.r = 0.5;
	next_color.g = 0.5;
	next_color.b = 0.5;
	drawing_rectangle = false;

	glutInit(&argc,argv);
	glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
	glutInitWindowSize(ImageW,ImageH);
	glutInitWindowPosition(100,100);
	glutCreateWindow("John Lake - Homework 2");
	init();	
	glutDisplayFunc(display);
	glutMouseFunc( mouseDraw );
	glutKeyboardFunc( keyboard );
	glutMainLoop();
	return 0;
}
